home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 2010 April / PCWorld0410.iso / pluginy Firefox / 4490 / 4490.xpi / chrome / wmn.jar / content / aes.js next >
Text File  |  2009-10-24  |  21KB  |  485 lines

  1. /* ***** BEGIN LICENSE BLOCK *****
  2.  *
  3.  * The code in this file was taken from the following web page
  4.  * http://www.movable-type.co.uk/scripts/aes.html
  5.  *
  6.  * In accordance with the intructions on the site I've added the following
  7.  * LGPL license block to it
  8.  *
  9.  * JavaScript Implementation of AES
  10.  * Copyright (C) 2005-2009 Chris Veness
  11.  *
  12.  * This library is free software; you can redistribute it and/or
  13.  * modify it under the terms of the GNU Lesser General Public
  14.  * License as published by the Free Software Foundation; either
  15.  * version 2.1 of the License, or (at your option) any later version.
  16.  *
  17.  * This library is distributed in the hope that it will be useful,
  18.  * but WITHOUT ANY WARRANTY; without even the implied warranty of
  19.  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  20.  * Lesser General Public License for more details.
  21.  *
  22.  * You should have received a copy of the GNU Lesser General Public
  23.  * License along with this library; if not, write to the Free Software
  24.  * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301  USA
  25.  *
  26.  * ***** END LICENSE BLOCK ***** */
  27.  
  28. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
  29. /*  AES implementation in JavaScript (c) Chris Veness 2005-2009                                   */
  30. /*   - see http://csrc.nist.gov/publications/PubsFIPS.html#197                                    */
  31. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
  32.  
  33. var Aes = {};  // Aes namespace
  34.  
  35. /**
  36.  * AES Cipher function: encrypt 'input' state with Rijndael algorithm
  37.  *   applies Nr rounds (10/12/14) using key schedule w for 'add round key' stage
  38.  *
  39.  * @param {Number[]} input 16-byte (128-bit) input state array
  40.  * @param {Number[][]} w   Key schedule as 2D byte-array (Nr+1 x Nb bytes)
  41.  * @returns {Number[]}     Encrypted output state array
  42.  */
  43. Aes.Cipher = function(input, w) {    // main Cipher function [í╫5.1]
  44.   var Nb = 4;               // block size (in words): no of columns in state (fixed at 4 for AES)
  45.   var Nr = w.length/Nb - 1; // no of rounds: 10/12/14 for 128/192/256-bit keys
  46.  
  47.   var state = [[],[],[],[]];  // initialise 4xNb byte-array 'state' with input [í╫3.4]
  48.   for (var i=0; i<4*Nb; i++) state[i%4][Math.floor(i/4)] = input[i];
  49.  
  50.   state = Aes.AddRoundKey(state, w, 0, Nb);
  51.  
  52.   for (var round=1; round<Nr; round++) {
  53.     state = Aes.SubBytes(state, Nb);
  54.     state = Aes.ShiftRows(state, Nb);
  55.     state = Aes.MixColumns(state, Nb);
  56.     state = Aes.AddRoundKey(state, w, round, Nb);
  57.   }
  58.  
  59.   state = Aes.SubBytes(state, Nb);
  60.   state = Aes.ShiftRows(state, Nb);
  61.   state = Aes.AddRoundKey(state, w, Nr, Nb);
  62.  
  63.   var output = new Array(4*Nb);  // convert state to 1-d array before returning [í╫3.4]
  64.   for (var i=0; i<4*Nb; i++) output[i] = state[i%4][Math.floor(i/4)];
  65.   return output;
  66. }
  67.  
  68. /**
  69.  * Perform Key Expansion to generate a Key Schedule
  70.  *
  71.  * @param {Number[]} key Key as 16/24/32-byte array
  72.  * @returns {Number[][]} Expanded key schedule as 2D byte-array (Nr+1 x Nb bytes)
  73.  */
  74. Aes.KeyExpansion = function(key) {  // generate Key Schedule (byte-array Nr+1 x Nb) from Key [í╫5.2]
  75.   var Nb = 4;            // block size (in words): no of columns in state (fixed at 4 for AES)
  76.   var Nk = key.length/4  // key length (in words): 4/6/8 for 128/192/256-bit keys
  77.   var Nr = Nk + 6;       // no of rounds: 10/12/14 for 128/192/256-bit keys
  78.  
  79.   var w = new Array(Nb*(Nr+1));
  80.   var temp = new Array(4);
  81.  
  82.   for (var i=0; i<Nk; i++) {
  83.     var r = [key[4*i], key[4*i+1], key[4*i+2], key[4*i+3]];
  84.     w[i] = r;
  85.   }
  86.  
  87.   for (var i=Nk; i<(Nb*(Nr+1)); i++) {
  88.     w[i] = new Array(4);
  89.     for (var t=0; t<4; t++) temp[t] = w[i-1][t];
  90.     if (i % Nk == 0) {
  91.       temp = Aes.SubWord(Aes.RotWord(temp));
  92.       for (var t=0; t<4; t++) temp[t] ^= Aes.Rcon[i/Nk][t];
  93.     } else if (Nk > 6 && i%Nk == 4) {
  94.       temp = Aes.SubWord(temp);
  95.     }
  96.     for (var t=0; t<4; t++) w[i][t] = w[i-Nk][t] ^ temp[t];
  97.   }
  98.  
  99.   return w;
  100. }
  101.  
  102. /*
  103.  * ---- remaining routines are private, not called externally ----
  104.  */
  105.  
  106. Aes.SubBytes = function(s, Nb) {    // apply SBox to state S [í╫5.1.1]
  107.   for (var r=0; r<4; r++) {
  108.     for (var c=0; c<Nb; c++) s[r][c] = Aes.Sbox[s[r][c]];
  109.   }
  110.   return s;
  111. }
  112.  
  113. Aes.ShiftRows = function(s, Nb) {    // shift row r of state S left by r bytes [í╫5.1.2]
  114.   var t = new Array(4);
  115.   for (var r=1; r<4; r++) {
  116.     for (var c=0; c<4; c++) t[c] = s[r][(c+r)%Nb];  // shift into temp copy
  117.     for (var c=0; c<4; c++) s[r][c] = t[c];         // and copy back
  118.   }          // note that this will work for Nb=4,5,6, but not 7,8 (always 4 for AES):
  119.   return s;  // see asmaes.sourceforge.net/rijndael/rijndaelImplementation.pdf
  120. }
  121.  
  122. Aes.MixColumns = function(s, Nb) {   // combine bytes of each col of state S [í╫5.1.3]
  123.   for (var c=0; c<4; c++) {
  124.     var a = new Array(4);  // 'a' is a copy of the current column from 's'
  125.     var b = new Array(4);  // 'b' is a.{02} in GF(2^8)
  126.     for (var i=0; i<4; i++) {
  127.       a[i] = s[i][c];
  128.       b[i] = s[i][c]&0x80 ? s[i][c]<<1 ^ 0x011b : s[i][c]<<1;
  129.     }
  130.     // a[n] ^ b[n] is a.{03} in GF(2^8)
  131.     s[0][c] = b[0] ^ a[1] ^ b[1] ^ a[2] ^ a[3]; // 2*a0 + 3*a1 + a2 + a3
  132.     s[1][c] = a[0] ^ b[1] ^ a[2] ^ b[2] ^ a[3]; // a0 * 2*a1 + 3*a2 + a3
  133.     s[2][c] = a[0] ^ a[1] ^ b[2] ^ a[3] ^ b[3]; // a0 + a1 + 2*a2 + 3*a3
  134.     s[3][c] = a[0] ^ b[0] ^ a[1] ^ a[2] ^ b[3]; // 3*a0 + a1 + a2 + 2*a3
  135.   }
  136.   return s;
  137. }
  138.  
  139. Aes.AddRoundKey = function(state, w, rnd, Nb) {  // xor Round Key into state S [í╫5.1.4]
  140.   for (var r=0; r<4; r++) {
  141.     for (var c=0; c<Nb; c++) state[r][c] ^= w[rnd*4+c][r];
  142.   }
  143.   return state;
  144. }
  145.  
  146. Aes.SubWord = function(w) {    // apply SBox to 4-byte word w
  147.   for (var i=0; i<4; i++) w[i] = Aes.Sbox[w[i]];
  148.   return w;
  149. }
  150.  
  151. Aes.RotWord = function(w) {    // rotate 4-byte word w left by one byte
  152.   var tmp = w[0];
  153.   for (var i=0; i<3; i++) w[i] = w[i+1];
  154.   w[3] = tmp;
  155.   return w;
  156. }
  157.  
  158. // Sbox is pre-computed multiplicative inverse in GF(2^8) used in SubBytes and KeyExpansion [í╫5.1.1]
  159. Aes.Sbox =  [0x63,0x7c,0x77,0x7b,0xf2,0x6b,0x6f,0xc5,0x30,0x01,0x67,0x2b,0xfe,0xd7,0xab,0x76,
  160.              0xca,0x82,0xc9,0x7d,0xfa,0x59,0x47,0xf0,0xad,0xd4,0xa2,0xaf,0x9c,0xa4,0x72,0xc0,
  161.              0xb7,0xfd,0x93,0x26,0x36,0x3f,0xf7,0xcc,0x34,0xa5,0xe5,0xf1,0x71,0xd8,0x31,0x15,
  162.              0x04,0xc7,0x23,0xc3,0x18,0x96,0x05,0x9a,0x07,0x12,0x80,0xe2,0xeb,0x27,0xb2,0x75,
  163.              0x09,0x83,0x2c,0x1a,0x1b,0x6e,0x5a,0xa0,0x52,0x3b,0xd6,0xb3,0x29,0xe3,0x2f,0x84,
  164.              0x53,0xd1,0x00,0xed,0x20,0xfc,0xb1,0x5b,0x6a,0xcb,0xbe,0x39,0x4a,0x4c,0x58,0xcf,
  165.              0xd0,0xef,0xaa,0xfb,0x43,0x4d,0x33,0x85,0x45,0xf9,0x02,0x7f,0x50,0x3c,0x9f,0xa8,
  166.              0x51,0xa3,0x40,0x8f,0x92,0x9d,0x38,0xf5,0xbc,0xb6,0xda,0x21,0x10,0xff,0xf3,0xd2,
  167.              0xcd,0x0c,0x13,0xec,0x5f,0x97,0x44,0x17,0xc4,0xa7,0x7e,0x3d,0x64,0x5d,0x19,0x73,
  168.              0x60,0x81,0x4f,0xdc,0x22,0x2a,0x90,0x88,0x46,0xee,0xb8,0x14,0xde,0x5e,0x0b,0xdb,
  169.              0xe0,0x32,0x3a,0x0a,0x49,0x06,0x24,0x5c,0xc2,0xd3,0xac,0x62,0x91,0x95,0xe4,0x79,
  170.              0xe7,0xc8,0x37,0x6d,0x8d,0xd5,0x4e,0xa9,0x6c,0x56,0xf4,0xea,0x65,0x7a,0xae,0x08,
  171.              0xba,0x78,0x25,0x2e,0x1c,0xa6,0xb4,0xc6,0xe8,0xdd,0x74,0x1f,0x4b,0xbd,0x8b,0x8a,
  172.              0x70,0x3e,0xb5,0x66,0x48,0x03,0xf6,0x0e,0x61,0x35,0x57,0xb9,0x86,0xc1,0x1d,0x9e,
  173.              0xe1,0xf8,0x98,0x11,0x69,0xd9,0x8e,0x94,0x9b,0x1e,0x87,0xe9,0xce,0x55,0x28,0xdf,
  174.              0x8c,0xa1,0x89,0x0d,0xbf,0xe6,0x42,0x68,0x41,0x99,0x2d,0x0f,0xb0,0x54,0xbb,0x16];
  175.  
  176. // Rcon is Round Constant used for the Key Expansion [1st col is 2^(r-1) in GF(2^8)] [í╫5.2]
  177. Aes.Rcon = [ [0x00, 0x00, 0x00, 0x00],
  178.              [0x01, 0x00, 0x00, 0x00],
  179.              [0x02, 0x00, 0x00, 0x00],
  180.              [0x04, 0x00, 0x00, 0x00],
  181.              [0x08, 0x00, 0x00, 0x00],
  182.              [0x10, 0x00, 0x00, 0x00],
  183.              [0x20, 0x00, 0x00, 0x00],
  184.              [0x40, 0x00, 0x00, 0x00],
  185.              [0x80, 0x00, 0x00, 0x00],
  186.              [0x1b, 0x00, 0x00, 0x00],
  187.              [0x36, 0x00, 0x00, 0x00] ];
  188.  
  189.  
  190. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
  191. /*  AES Counter-mode implementation in JavaScript (c) Chris Veness 2005-2009                      */
  192. /*   - see http://csrc.nist.gov/publications/nistpubs/800-38a/sp800-38a.pdf                       */
  193. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
  194.  
  195. var AesCtr = {};  // AesCtr namespace
  196.  
  197. /**
  198.  * Encrypt a text using AES encryption in Counter mode of operation
  199.  *
  200.  * Unicode multi-byte character safe
  201.  *
  202.  * @param {String} plaintext Source text to be encrypted
  203.  * @param {String} password  The password to use to generate a key
  204.  * @param {Number} nBits     Number of bits to be used in the key (128, 192, or 256)
  205.  * @returns {string}         Encrypted text
  206.  */
  207. AesCtr.encrypt = function(plaintext, password, nBits) {
  208.   var blockSize = 16;  // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
  209.   if (!(nBits==128 || nBits==192 || nBits==256)) return '';  // standard allows 128/192/256 bit keys
  210.   plaintext = Utf8.encode(plaintext);
  211.   password = Utf8.encode(password);
  212.   //var t = new Date();  // timer
  213.  
  214.   // use AES itself to encrypt password to get cipher key (using plain password as source for key
  215.   // expansion) - gives us well encrypted key
  216.   var nBytes = nBits/8;  // no bytes in key
  217.   var pwBytes = new Array(nBytes);
  218.   for (var i=0; i<nBytes; i++) {
  219.     pwBytes[i] = isNaN(password.charCodeAt(i)) ? 0 : password.charCodeAt(i);
  220.   }
  221.   var key = Aes.Cipher(pwBytes, Aes.KeyExpansion(pwBytes));  // gives us 16-byte key
  222.   key = key.concat(key.slice(0, nBytes-16));  // expand key to 16/24/32 bytes long
  223.  
  224.   // initialise counter block (NIST SP800-38A í╫B.2): millisecond time-stamp for nonce in 1st 8 bytes,
  225.   // block counter in 2nd 8 bytes
  226.   var counterBlock = new Array(blockSize);
  227.   var nonce = (new Date()).getTime();  // timestamp: milliseconds since 1-Jan-1970
  228.   var nonceSec = Math.floor(nonce/1000);
  229.   var nonceMs = nonce%1000;
  230.   // encode nonce with seconds in 1st 4 bytes, and (repeated) ms part filling 2nd 4 bytes
  231.   for (var i=0; i<4; i++) counterBlock[i] = (nonceSec >>> i*8) & 0xff;
  232.   for (var i=0; i<4; i++) counterBlock[i+4] = nonceMs & 0xff;
  233.   // and convert it to a string to go on the front of the ciphertext
  234.   var ctrTxt = '';
  235.   for (var i=0; i<8; i++) ctrTxt += String.fromCharCode(counterBlock[i]);
  236.  
  237.   // generate key schedule - an expansion of the key into distinct Key Rounds for each round
  238.   var keySchedule = Aes.KeyExpansion(key);
  239.  
  240.   var blockCount = Math.ceil(plaintext.length/blockSize);
  241.   var ciphertxt = new Array(blockCount);  // ciphertext as array of strings
  242.  
  243.   for (var b=0; b<blockCount; b++) {
  244.     // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
  245.     // done in two stages for 32-bit ops: using two words allows us to go past 2^32 blocks (68GB)
  246.     for (var c=0; c<4; c++) counterBlock[15-c] = (b >>> c*8) & 0xff;
  247.     for (var c=0; c<4; c++) counterBlock[15-c-4] = (b/0x100000000 >>> c*8)
  248.  
  249.     var cipherCntr = Aes.Cipher(counterBlock, keySchedule);  // -- encrypt counter block --
  250.  
  251.     // block size is reduced on final block
  252.     var blockLength = b<blockCount-1 ? blockSize : (plaintext.length-1)%blockSize+1;
  253.     var cipherChar = new Array(blockLength);
  254.  
  255.     for (var i=0; i<blockLength; i++) {  // -- xor plaintext with ciphered counter char-by-char --
  256.       cipherChar[i] = cipherCntr[i] ^ plaintext.charCodeAt(b*blockSize+i);
  257.       cipherChar[i] = String.fromCharCode(cipherChar[i]);
  258.     }
  259.     ciphertxt[b] = cipherChar.join('');
  260.   }
  261.  
  262.   // Array.join is more efficient than repeated string concatenation in IE
  263.   var ciphertext = ctrTxt + ciphertxt.join('');
  264.   ciphertext = Base64.encode(ciphertext);  // encode in base64
  265.  
  266.   //alert((new Date()) - t);
  267.   return ciphertext;
  268. }
  269.  
  270. /**
  271.  * Decrypt a text encrypted by AES in counter mode of operation
  272.  *
  273.  * @param {String} ciphertext Source text to be encrypted
  274.  * @param {String} password   The password to use to generate a key
  275.  * @param {Number} nBits      Number of bits to be used in the key (128, 192, or 256)
  276.  * @returns {String}          Decrypted text
  277.  */
  278. AesCtr.decrypt = function(ciphertext, password, nBits) {
  279.   var blockSize = 16;  // block size fixed at 16 bytes / 128 bits (Nb=4) for AES
  280.   if (!(nBits==128 || nBits==192 || nBits==256)) return '';  // standard allows 128/192/256 bit keys
  281.   ciphertext = Base64.decode(ciphertext);
  282.   password = Utf8.encode(password);
  283.   //var t = new Date();  // timer
  284.  
  285.   // use AES to encrypt password (mirroring encrypt routine)
  286.   var nBytes = nBits/8;  // no bytes in key
  287.   var pwBytes = new Array(nBytes);
  288.   for (var i=0; i<nBytes; i++) {
  289.     pwBytes[i] = isNaN(password.charCodeAt(i)) ? 0 : password.charCodeAt(i);
  290.   }
  291.   var key = Aes.Cipher(pwBytes, Aes.KeyExpansion(pwBytes));
  292.   key = key.concat(key.slice(0, nBytes-16));  // expand key to 16/24/32 bytes long
  293.  
  294.   // recover nonce from 1st 8 bytes of ciphertext
  295.   var counterBlock = new Array(8);
  296.   ctrTxt = ciphertext.slice(0, 8);
  297.   for (var i=0; i<8; i++) counterBlock[i] = ctrTxt.charCodeAt(i);
  298.  
  299.   // generate key schedule
  300.   var keySchedule = Aes.KeyExpansion(key);
  301.  
  302.   // separate ciphertext into blocks (skipping past initial 8 bytes)
  303.   var nBlocks = Math.ceil((ciphertext.length-8) / blockSize);
  304.   var ct = new Array(nBlocks);
  305.   for (var b=0; b<nBlocks; b++) ct[b] = ciphertext.slice(8+b*blockSize, 8+b*blockSize+blockSize);
  306.   ciphertext = ct;  // ciphertext is now array of block-length strings
  307.  
  308.   // plaintext will get generated block-by-block into array of block-length strings
  309.   var plaintxt = new Array(ciphertext.length);
  310.  
  311.   for (var b=0; b<nBlocks; b++) {
  312.     // set counter (block #) in last 8 bytes of counter block (leaving nonce in 1st 8 bytes)
  313.     for (var c=0; c<4; c++) counterBlock[15-c] = ((b) >>> c*8) & 0xff;
  314.     for (var c=0; c<4; c++) counterBlock[15-c-4] = (((b+1)/0x100000000-1) >>> c*8) & 0xff;
  315.  
  316.     var cipherCntr = Aes.Cipher(counterBlock, keySchedule);  // encrypt counter block
  317.  
  318.     var plaintxtByte = new Array(ciphertext[b].length);
  319.     for (var i=0; i<ciphertext[b].length; i++) {
  320.       // -- xor plaintxt with ciphered counter byte-by-byte --
  321.       plaintxtByte[i] = cipherCntr[i] ^ ciphertext[b].charCodeAt(i);
  322.       plaintxtByte[i] = String.fromCharCode(plaintxtByte[i]);
  323.     }
  324.     plaintxt[b] = plaintxtByte.join('');
  325.   }
  326.  
  327.   // join array of blocks into single plaintext string
  328.   var plaintext = plaintxt.join('');
  329.   plaintext = Utf8.decode(plaintext);  // decode from UTF8 back to Unicode multi-byte chars
  330.  
  331.   //alert((new Date()) - t);
  332.   return plaintext;
  333. }
  334.  
  335.  
  336. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
  337. /*  Base64 class: Base 64 encoding / decoding (c) Chris Veness 2002-2009                          */
  338. /*    note: depends on Utf8 class                                                                 */
  339. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
  340.  
  341. var Base64 = {};  // Base64 namespace
  342.  
  343. Base64.code = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=";
  344.  
  345. /**
  346.  * Encode string into Base64, as defined by RFC 4648 [http://tools.ietf.org/html/rfc4648]
  347.  * (instance method extending String object). As per RFC 4648, no newlines are added.
  348.  *
  349.  * @param {String} str The string to be encoded as base-64
  350.  * @param {Boolean} [utf8encode=false] Flag to indicate whether str is Unicode string to be encoded
  351.  *   to UTF8 before conversion to base64; otherwise string is assumed to be 8-bit characters
  352.  * @returns {String} Base64-encoded string
  353.  */
  354. Base64.encode = function(str, utf8encode) {  // http://tools.ietf.org/html/rfc4648
  355.   utf8encode =  (typeof utf8encode == 'undefined') ? false : utf8encode;
  356.   var o1, o2, o3, bits, h1, h2, h3, h4, e=[], pad = '', c, plain, coded;
  357.   var b64 = Base64.code;
  358.  
  359.   plain = utf8encode ? str.encodeUTF8() : str;
  360.  
  361.   c = plain.length % 3;  // pad string to length of multiple of 3
  362.   if (c > 0) { while (c++ < 3) { pad += '='; plain += '\0'; } }
  363.   // note: doing padding here saves us doing special-case packing for trailing 1 or 2 chars
  364.  
  365.   for (c=0; c<plain.length; c+=3) {  // pack three octets into four hexets
  366.     o1 = plain.charCodeAt(c);
  367.     o2 = plain.charCodeAt(c+1);
  368.     o3 = plain.charCodeAt(c+2);
  369.  
  370.     bits = o1<<16 | o2<<8 | o3;
  371.  
  372.     h1 = bits>>18 & 0x3f;
  373.     h2 = bits>>12 & 0x3f;
  374.     h3 = bits>>6 & 0x3f;
  375.     h4 = bits & 0x3f;
  376.  
  377.     // use hextets to index into code string
  378.     e[c/3] = b64.charAt(h1) + b64.charAt(h2) + b64.charAt(h3) + b64.charAt(h4);
  379.   }
  380.   coded = e.join('');  // join() is far faster than repeated string concatenation in IE
  381.  
  382.   // replace 'A's from padded nulls with '='s
  383.   coded = coded.slice(0, coded.length-pad.length) + pad;
  384.  
  385.   return coded;
  386. }
  387.  
  388. /**
  389.  * Decode string from Base64, as defined by RFC 4648 [http://tools.ietf.org/html/rfc4648]
  390.  * (instance method extending String object). As per RFC 4648, newlines are not catered for.
  391.  *
  392.  * @param {String} str The string to be decoded from base-64
  393.  * @param {Boolean} [utf8decode=false] Flag to indicate whether str is Unicode string to be decoded
  394.  *   from UTF8 after conversion from base64
  395.  * @returns {String} decoded string
  396.  */
  397. Base64.decode = function(str, utf8decode) {
  398.   utf8decode =  (typeof utf8decode == 'undefined') ? false : utf8decode;
  399.   var o1, o2, o3, h1, h2, h3, h4, bits, d=[], plain, coded;
  400.   var b64 = Base64.code;
  401.  
  402.   coded = utf8decode ? str.decodeUTF8() : str;
  403.  
  404.  
  405.   for (var c=0; c<coded.length; c+=4) {  // unpack four hexets into three octets
  406.     h1 = b64.indexOf(coded.charAt(c));
  407.     h2 = b64.indexOf(coded.charAt(c+1));
  408.     h3 = b64.indexOf(coded.charAt(c+2));
  409.     h4 = b64.indexOf(coded.charAt(c+3));
  410.  
  411.     bits = h1<<18 | h2<<12 | h3<<6 | h4;
  412.  
  413.     o1 = bits>>>16 & 0xff;
  414.     o2 = bits>>>8 & 0xff;
  415.     o3 = bits & 0xff;
  416.  
  417.     d[c/4] = String.fromCharCode(o1, o2, o3);
  418.     // check for padding
  419.     if (h4 == 0x40) d[c/4] = String.fromCharCode(o1, o2);
  420.     if (h3 == 0x40) d[c/4] = String.fromCharCode(o1);
  421.   }
  422.   plain = d.join('');  // join() is far faster than repeated string concatenation in IE
  423.  
  424.   return utf8decode ? plain.decodeUTF8() : plain;
  425. }
  426.  
  427.  
  428. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
  429. /*  Utf8 class: encode / decode between multi-byte Unicode characters and UTF-8 multiple          */
  430. /*              single-byte character encoding (c) Chris Veness 2002-2009                         */
  431. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
  432.  
  433. var Utf8 = {};  // Utf8 namespace
  434.  
  435. /**
  436.  * Encode multi-byte Unicode string into utf-8 multiple single-byte characters
  437.  * (BMP / basic multilingual plane only)
  438.  *
  439.  * Chars in range U+0080 - U+07FF are encoded in 2 chars, U+0800 - U+FFFF in 3 chars
  440.  *
  441.  * @param {String} strUni Unicode string to be encoded as UTF-8
  442.  * @returns {String} encoded string
  443.  */
  444. Utf8.encode = function(strUni) {
  445.   // use regular expressions & String.replace callback function for better efficiency
  446.   // than procedural approaches
  447.   var strUtf = strUni.replace(
  448.       /[\u0080-\u07ff]/g,  // U+0080 - U+07FF => 2 bytes 110yyyyy, 10zzzzzz
  449.       function(c) {
  450.         var cc = c.charCodeAt(0);
  451.         return String.fromCharCode(0xc0 | cc>>6, 0x80 | cc&0x3f); }
  452.     );
  453.   strUtf = strUtf.replace(
  454.       /[\u0800-\uffff]/g,  // U+0800 - U+FFFF => 3 bytes 1110xxxx, 10yyyyyy, 10zzzzzz
  455.       function(c) {
  456.         var cc = c.charCodeAt(0);
  457.         return String.fromCharCode(0xe0 | cc>>12, 0x80 | cc>>6&0x3F, 0x80 | cc&0x3f); }
  458.     );
  459.   return strUtf;
  460. }
  461.  
  462. /**
  463.  * Decode utf-8 encoded string back into multi-byte Unicode characters
  464.  *
  465.  * @param {String} strUtf UTF-8 string to be decoded back to Unicode
  466.  * @returns {String} decoded string
  467.  */
  468. Utf8.decode = function(strUtf) {
  469.   var strUni = strUtf.replace(
  470.       /[\u00c0-\u00df][\u0080-\u00bf]/g,                 // 2-byte chars
  471.       function(c) {  // (note parentheses for precence)
  472.         var cc = (c.charCodeAt(0)&0x1f)<<6 | c.charCodeAt(1)&0x3f;
  473.         return String.fromCharCode(cc); }
  474.     );
  475.   strUni = strUni.replace(
  476.       /[\u00e0-\u00ef][\u0080-\u00bf][\u0080-\u00bf]/g,  // 3-byte chars
  477.       function(c) {  // (note parentheses for precence)
  478.         var cc = ((c.charCodeAt(0)&0x0f)<<12) | ((c.charCodeAt(1)&0x3f)<<6) | ( c.charCodeAt(2)&0x3f);
  479.         return String.fromCharCode(cc); }
  480.     );
  481.   return strUni;
  482. }
  483.  
  484. /* - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - -  */
  485.